﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "GmRadialPatternActionBehavior.h"
#include "IActionInputEventArgs.h"
#include "IUiView.h"
#include "IUiDocument.h"
#include "IDocument.h"
#include "IUserTransaction.h"
#include "UiCommonDialog.h"
#include "ISelection.h"
#include "ICopyOperator.h"
#include "IElement.h"
#include "IRegenerator.h"
#include "IElementCopyPasteComponent.h"

#include "IRadioButtonGroupDefinition.h"
#include "ILineEditDefinition.h"
#include "IControlDefinition.h"

#include "IElementTransformationComponent.h"
#include "IHighlights.h"
#include "ElementJoinUtils.h"
#include "GbmpJoinUtils.h"
#include "IBehaviorConfig.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gcmp;

#define ACTION_RADIO_ROTATE_CENTER         L"gmRadioRotateCenter"
#define ACTION_EDIT_ARRAY_COUNT            L"gmEditArrayCount"
#define ACTION_RADIO_ARRAY_TYPE            L"gmRadioArrayType"
#define ACTION_EDIT_ANGLE                  L"gmEditAngle"

namespace
{
    std::wstring s_Rotate_Center_Custom = GBMP_TR(L"指定中心");
    std::wstring s_Rotate_Center_Default = GBMP_TR(L"默认中心");
    std::wstring s_Array_Angle_Second = GBMP_TR(L"间隔角度");
    std::wstring s_Array_Angle_Last = GBMP_TR(L"整体角度");
}

int GmRadialPatternActionBehavior::S_arrayCount = 3;
GmRadialPatternActionBehavior::GmRadialPatternActionBehavior() 
{
    if (IBehaviorConfig::GetConfigRecordValueAsString(L"KeepPreEditValue") == L"true")
    {
        m_sRetValue.m_arrayCount = GmRadialPatternActionBehavior::S_arrayCount;
    }
    else
    {
        m_sRetValue.m_arrayCount = 3;
    }
}

GmRadialPatternActionBehavior::~GmRadialPatternActionBehavior()
{
    if (IBehaviorConfig::GetConfigRecordValueAsString(L"KeepPreEditValue") == L"true")
    {
        GmRadialPatternActionBehavior::S_arrayCount = m_sRetValue.m_arrayCount;
    }
}

bool GmRadialPatternActionBehavior::DefineInputDialog(std::wstring &title, std::vector<OwnerPtr<IControlDefinition>>& inputItems)
{
    title = GBMP_TR(L"径向阵列");

    // 旋转中心
    {
        OwnerPtr<IRadioButtonGroupDefinition> opRotateCenterGroup = IRadioButtonGroupDefinition::Create(ACTION_RADIO_ROTATE_CENTER, GBMP_TR(L"旋转中心"));
        opRotateCenterGroup->AddRadioButton(s_Rotate_Center_Custom, s_Rotate_Center_Custom, s_Rotate_Center_Custom);
        opRotateCenterGroup->AddRadioButton(s_Rotate_Center_Default, s_Rotate_Center_Default, s_Rotate_Center_Default);
        opRotateCenterGroup->SetCurrentRadioButton(s_Rotate_Center_Default);
        inputItems.push_back(TransferOwnership(opRotateCenterGroup));
    }

    // 阵列个数
    {
        OwnerPtr<ILineEditDefinition> pLineEditArrayNum = ILineEditDefinition::Create(ACTION_EDIT_ARRAY_COUNT, GBMP_TR(L"阵列个数"), LineEditInputType::InputInt);
        std::wstring sArrayCount = StringUtil::FormatWString(L"%d", m_sRetValue.m_arrayCount);
        pLineEditArrayNum->SetText(sArrayCount);
        inputItems.push_back(TransferOwnership(pLineEditArrayNum));
    }

    // 阵列方式
    {
        OwnerPtr<IRadioButtonGroupDefinition> opRotateArrayType = IRadioButtonGroupDefinition::Create(ACTION_RADIO_ARRAY_TYPE, GBMP_TR(L"阵列方式"));
        opRotateArrayType->AddRadioButton(s_Array_Angle_Second, s_Array_Angle_Second, s_Array_Angle_Second);
        opRotateArrayType->AddRadioButton(s_Array_Angle_Last, s_Array_Angle_Last, s_Array_Angle_Last);
        opRotateArrayType->SetCurrentRadioButton(s_Array_Angle_Second);
        inputItems.push_back(TransferOwnership(opRotateArrayType));
    }

    // 角度
    {
        OwnerPtr<ILineEditDefinition> pLineEditArrayAngle = ILineEditDefinition::Create(ACTION_EDIT_ANGLE, GBMP_TR(L"角度"), LineEditInputType::InputDouble);
        pLineEditArrayAngle->SetText(std::wstring(L"0"));
        inputItems.push_back(TransferOwnership(pLineEditArrayAngle));
    }

    return true;
}

bool GmRadialPatternActionBehavior::OnActionInputEvent(IActionInputEventArgs* pArgs, EnRadialPatternInputEvent& eventType, sDefineConfigRPB& RetValue)
{
    const std::pair<std::wstring, Any>& msg = pArgs->GetInputMessage();
    const std::wstring eventID = msg.first;
    Any inputValue = msg.second;

    if (pArgs->GetType() == ActionInputEventType::InputValueChanged)
    {
        if (eventID == ACTION_RADIO_ROTATE_CENTER)
        {
            eventType = EnRadialPatternInputEvent::INPUT_EVENT_RADARR_ROTATE_CENTER;
            if (inputValue.cast<std::wstring>() == s_Rotate_Center_Custom)//选择指定中心
            {
                RetValue.m_autoCenter = false;
            }
            else
            {
                RetValue.m_autoCenter = true;
            }
        }
        else if (eventID == ACTION_EDIT_ARRAY_COUNT)
        {
            eventType = EnRadialPatternInputEvent::INPUT_EVENT_RADARR_ARRAY_COUNT;
            RetValue.m_arrayCount = inputValue.cast<int>();
            m_sRetValue.m_arrayCount = RetValue.m_arrayCount;
        }
        else if (eventID == ACTION_RADIO_ARRAY_TYPE)
        {
            eventType = EnRadialPatternInputEvent::INPUT_EVENT_RADARR_ARRAY_TYPE;
            std::wstring angleType1 = inputValue.cast<std::wstring>();
            if (angleType1 == s_Array_Angle_Second)
            {
                RetValue.m_angleType = EnRadialArrayAngleType::RES_ANGLE_SECOND;
            }
            else
            {
                RetValue.m_angleType = EnRadialArrayAngleType::RES_ANGLE_LAST;
            }
        }
        else if (eventID == ACTION_EDIT_ANGLE)
        {
            eventType = EnRadialPatternInputEvent::INPUT_EVENT_RADARR_ANGLE;
            RetValue.m_angle = inputValue.cast<double>() / 180.0 * Constants::MATH_PI;
        }
    }
    else if (pArgs->GetType() == ActionInputEventType::InputEnterFinished)
    {
        //只需要 响应角度的回车消息
        if (eventID == ACTION_EDIT_ANGLE)
        {
            eventType = EnRadialPatternInputEvent::INPUT_EVENT_RADARR_ANGLE;
            RetValue.m_angle = inputValue.cast<double>() / 180.0 * Constants::MATH_PI;
        }
    }
    return false;
}

bool GmRadialPatternActionBehavior::DefinePromptMsg(std::wstring& promptMsg, const EnRadialArrayStatus enStatus)
{
    switch (enStatus)
    {
    case EnRadialArrayStatus::RES_Getting_StartPoint:
        promptMsg = GBMP_TR(L"径向阵列选中物体 - 请输入旋转角度起点");
        break;
    case EnRadialArrayStatus::RES_Getting_EndPoint:
        promptMsg = GBMP_TR(L"径向阵列选中物体 - 请输入旋转角度终点");
        break;
    case EnRadialArrayStatus::RES_Getting_CenterPoint:
        promptMsg = GBMP_TR(L"径向阵列选中物体 - 请输入旋转中心点");
        break;
    default:
        break;
    }
    return true;
}

bool GmRadialPatternActionBehavior::DefineCursorType(CursorType& cursorType, const EnRadialArrayStatus enStatus)
{
    cursorType = CursorType::ArrowCursor;
    return true;
}

bool GmRadialPatternActionBehavior::OnEnterGettingPointState(IUiView* pCurrentView, const EnRadialArrayStatus enStatus)
{
    return false;
}

bool GmRadialPatternActionBehavior::OnInitAction(IUiView* pCurrentView)
{
    return false;
}

bool GmRadialPatternActionBehavior::OnActionFinished(IUiView* pCurrentView)
{
    return false;
}

bool GmRadialPatternActionBehavior::OnDestroyAction()
{
    return false;
}

bool GmRadialPatternActionBehavior::GetPreviewGRepOnPickPointUpdated(EnRadialArrayStatus& enStatus, IUiView* pCurrentView, const Vector3d& pos, OwnerPtr<IGraphicsNodeGroup>& opGNodeGroup)
{
    if (enStatus == EnRadialArrayStatus::RES_Getting_StartPoint)
    {
        return false;
    }
    else if (enStatus == EnRadialArrayStatus::RES_Getting_EndPoint)
    {
        return false;
    }
    return false;
}

int GmRadialPatternActionBehavior::RadialArrayElements(IUiView* pCurrentView, std::vector<ElementId>& selectedModelIds, const Vector3d& rotateAxis, sDefineConfigRPB RetValue)
{
    IUiDocument*  pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_UNLESS(pUiDoc != nullptr, 0, L"pUiDoc为空",L"GDMPLab",L"2024-03-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc != nullptr, 0, L"pDoc为空",L"GDMPLab",L"2024-03-30");

    if (MathUtils::IsEqual(RetValue.m_angle, 0, Constants::DOUBLE_EPS))
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"径向阵列"), GBMP_TR(L"旋转角度为0，请重新输入！"), (int)UiCommonDialog::ButtonType::OK);
        return false;
    }

    std::vector<ElementId> selectedElementIds;
    FOR_EACH(elementId, selectedModelIds)
    {
        const IElement* pElement = pDoc->GetElement(elementId);
        if (!pElement)
        {
            continue;
        }

        if (const IElementTransformationComponent *pElementTransformationComponent = pElement->GetElementTransformationComponent())
        {
            if (const IElementCopyPasteComponent* pElementCopyPasteComponent = pElement->GetCopyPasteComponent())
            {
                std::wstring cannotArrayedExplanation;
                if (pElementTransformationComponent->CanBeRotated(&cannotArrayedExplanation) &&
                    pElementCopyPasteComponent->CanBeCopied(&cannotArrayedExplanation))
                {
                    selectedElementIds.emplace_back(elementId);
                }
            }
        }
    }

    if (selectedElementIds.empty())
    {
        UiCommonDialog::ShowMessageBox(GBMP_TR(L"径向阵列"), GBMP_TR(L"没有满足条件的阵列对象。"), static_cast<int>(UiCommonDialog::ButtonType::OK));
        return false;
    }

    OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, GBMP_TR(L"旋径向阵列选中物体"), true);
    DBG_WARN_AND_RETURN_UNLESS(ut.get() != nullptr, 0, L"ut为空",L"GDMPLab",L"2024-03-30");

    double angleInRadian = RetValue.m_angle;
    if (RetValue.m_angleType == EnRadialArrayAngleType::RES_ANGLE_LAST)
    {
        angleInRadian /= (RetValue.m_arrayCount - 1);
    }

    std::vector<ElementId> allnewEleIdVec;

    const ICopyOperator* pDefaultCopyOperator = ICopyOperator::Get();
    DBG_WARN_UNLESS(pDefaultCopyOperator != nullptr, L"默认的拷贝器不应该为空",L"GDMPLab",L"2024-03-30");
    for (int i = 1; i < RetValue.m_arrayCount; i++)
    {
        const std::vector<ElementId>& toRoateModelIds = pDefaultCopyOperator->CopyElements(dynamic_cast<IDocument*>(pDoc), selectedElementIds, std::map<ElementId, ElementId>(), nullptr);
        FOR_EACH(elementId, toRoateModelIds)
        {
            IElement* pElem = pDoc->GetElement(elementId);
            //注意：洞口和依赖的Host同时环阵，洞口本身相对位置关系已经正确，无需变换 
            if (pElem->GetHostElementId().IsValid() &&
                std::find(toRoateModelIds.begin(), toRoateModelIds.end(), pElem->GetHostElementId()) != toRoateModelIds.end())
            {
                // 跳过变换关系
            }
            else
            {
                IElementTransformationComponent *pElementTransformationComponent = pElem->GetElementTransformationComponent();
                if (!pElementTransformationComponent)
                    continue;
                pElementTransformationComponent->Rotate(RetValue.m_centerPt, rotateAxis, angleInRadian*i);
            }

            pElem->GetDocument()->GetRegenerator()->RegenerateElement(pElem->GetElementId());

            ElementJoinUtils::DeleteAllElementJoins(pDoc, elementId);
            GbmpJoinUtils::CreateJoinsAndCuts(pDoc, elementId);

            allnewEleIdVec.push_back(elementId);
        }
    }

    //// 全部阵列完统一执行一次约束解算即可
    //std::set<const gfam::FamConstraint*> failedConstraints;
    //bool result = gfam::ConstraintUtility::SolveCopiedElementsWithRotation(pDoc, allnewEleIdVec, failedConstraints);
    //FOR_EACH(failedConstraint, failedConstraints)
    //{
    //    pDoc->DeleteElement(failedConstraint->GetBasicInformation()->GetElementId());
    //}
    //// 更新约束辅助对象
    //gfam::ConstraintUtility::ShowConstraintSymbolOfElements(pDoc, allnewEleIdVec);

    ut->Commit();

    GraphicsNodeReferenceOwnerPtrSet newSelections;
    std::vector<OwnerPtr<IGraphicsNodeReference>> newHighlights;
    FOR_EACH(elementId, allnewEleIdVec)
    {
        if (elementId.IsValid())
        {
            OwnerPtr<IGraphicsNodeReference> opGnodeRef = IGraphicsNodeReference::CreateGraphicsElementShapeReference(elementId);
            newSelections.insert(opGnodeRef->Clone());
            newHighlights.push_back(TransferOwnership(opGnodeRef));
        }
        else
        {
            DBG_WARN(L"elementId invalid",L"GDMPLab",L"2024-03-30");
        }
    }

    // 集中设置，减少由选择集、高亮集变更引起的性能问题
    ISelection::Get()->AddGroupGraphicsNodeReference(pDoc, newSelections);
    IHighlights::Get()->AddGraphicsNodeReferences(newHighlights);

    return true;
}
